# -*- coding=utf-8 -*-

import requests
import lxml.etree as le
import re
import os
import time
from threading import RLock
from concurrent.futures import ThreadPoolExecutor, wait, ALL_COMPLETED, as_completed
import sqlite3

class download_dytt_videos():

    def __init__(self, kw_list, save_path = os.getcwd()):
        self.kw_list = kw_list
        self.save_path = save_path
        self.headers = {
            'User-Agent' : 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:80.0) Gecko/20100101 Firefox/80.0'
        }
        self.major_url = 'https://www.dytt.com'
        self.result = []
        self.iu_list = {}
        self.conn, self.cursor = self.__init_db__()
        self.ThreadPool = ThreadPoolExecutor(max_workers=10)
        self.task_list = {}
        self.lock = RLock()
        if not os.path.exists('./cache'):
            os.mkdir('./cache')

    def __init_db__(self):
        '''
        初始化缓存数据库
        :return: bool
        '''
        while True:
            try:
                db = input('请输入缓存数据库路径:')
                conn = sqlite3.connect(db)
                print("Opened database successfully")
                break
            except sqlite3.OperationalError:
                print('Unable to open database file')
                if input('是否继续(y/n):') in ['y', 'Y']:
                    continue
                else:
                    conn = sqlite3.connect('cache.db')
                    break
        cursor = conn.cursor()
        sql = 'create table if not exists Cache(Keywords varchar(30) UNIQUE , Data TEXT NOT NULL)'
        cursor.execute(sql)
        print('Create table successfully')
        conn.commit()
        return conn, cursor

    def __thread_processing(self):
        '''

        :return:
        '''
        for task in as_completed(self.task_list.values()):
            if task.done():
                data = list(self.task_list.keys())[list(x for x in self.task_list.values()).index(task)]
                del self.task_list[data]
                print(f'request to {data} finished, result is {task.result()}')
                with open('process.log', 'a') as f:
                    f.write(f'request to {data} finished, result is {task.result()}, time is {time.asctime()}\n')

    def _threading(self, func, *iterable, **kwargs):
        '''
        利用线程池开启多线程
        :param func:
        :param iterable:
        :param kwargs:
        :return:
        '''
        for data in iterable:
            kwargs['data'] = data
            self.lock.acquire()
            task = self.ThreadPool.submit(func, **kwargs)
            self.lock.release()
            name = data['name'] if type(data) == dict else data
            print('func: %s data: %s is starting' % (func.__name__, name))
            name = data['name'] if type(data) == dict else data
            self.task_list[name] = task
        wait(self.task_list.values(), return_when=ALL_COMPLETED)
        self.__thread_processing()

    def __operate_cache(self, url, method, data=None):
        '''
        本函数用来查找缓存
        :param kw:
        :return:
        '''
        if method == 'select':
            self.cursor.execute('select Data from where Keyword=?', url)
            return self.cursor.fetchone()[1]
        elif method == 'insert':
            self.cursor.execute('insert into Cache value (?, ?)', (url, data))
        elif method == 'update'

    def get_response(self, url):
        '''
        本函数用来处理请求
        :param url:要请求的链接地址
        :return:页面内容
        '''
        cache_exist = self.__operate_cache(url, 'select')
        if cache_exist:
            with open(cache_exist, 'r', encoding='utf-8') as f:
                return f.read()
        count = 0
        response = ''
        while count < 5:
            try:
                response = requests.get(url, headers=self.headers)
                break
            except ConnectionError:
                count += 1
                time.sleep(0.5)
                continue
        if count == 5 and response == '':
            print('网络不好...')
            return
        print(re.findall('<title>(.*?)</title>', response.text))
        title = re.findall("(.*?)[\|(.*?)]* - .*电影淘淘", re.findall('<title>(.*?)</title>', response.text)[0])[0].split('|')[0]
        f_path = './cache/%s.html' % title
        with open(f_path, 'wb') as f:
            f.write(response.content)
        self.__operate_cache(url, 'insert', f_path)
        return response.text

    def search(self, **kwargs):
        '''
        本函数用来搜索关键词，并由用户选择要下载的视频
        :param kw: 要搜索的关键词
        :return: 选择后的视频的简介页的链接
        '''
        def s(data):
            url = 'https://www.dytt.com/vodsearch/-------------.html?wd=%s' % data
            count = 5
            result = []
            print(url)
            text = ''
            while count > 0:
                try:
                    text = self.get_response(url=url)
                    break
                except:
                    print('正在重试...')
                    time.sleep(1.3)
                    count -= 1
            if text:
                self.lock.acquire()
                print('{:2s}: {:^30s}\t{:^50s}\t{:^10s}'.format('序号', '搜索结果名称', '搜索结果类型', '上映时间'))
                for i, uc in enumerate(le.HTML(text).xpath('//tr')[1:]):
                    name = uc.xpath('./td[1]/a/text()')[0]
                    url = self.major_url + uc.xpath('./td[1]/a/@href')[0]
                    v_type = uc.xpath('./td[2]/text()')
                    v_type = v_type[0] if len(v_type) != 0 else ''
                    r_time = uc.xpath('./td[5]/text()')[0]
                    result.append(
                        {
                            'name': name,
                            'url': url
                        }
                    )
                    print('{:>2d}: {:^30s} {:^50s} {:^10s}'.format(i + 1, name, v_type, r_time))
                while True:
                    try:
                        choose = tuple([eval(x) - 1 for x in input('请选择要下载的视频序号(以空格分隔)：').split()])
                        break
                    except:
                        print('输入错误')
                        continue
                map(lambda x: self.__operate_cache(), [result[i] for i in choose])
                [self.result.append(result[i]) for i in choose]
                self.lock.release()
            else:
                print('网络不好，请稍后重试...')

        return self._threading(s, *self.kw_list, **kwargs)

    def get_index_url(self, **kwargs):
        '''
        本函数用来获得每个视频的播放页
        :param url: 视频的简介页的链接
        :return: 每个视频播放页的的链接
        '''
        def giu(data):
            name = data['name']
            url = data['url']
            cache_exist = self.req_engine.get(url)
            if cache_exist:

            self.iu_list[name] = []
            content = self.get_response(url=url)
            video_list = le.HTML(content).xpath('//ul[@class="bofangListUl"]/li/a')
            for i, video in enumerate(video_list):
                url = self.major_url + video.xpath('./@href')[0]
                v_name = video.xpath('./text()')[0]
                self.iu_list[name].append(
                    {
                        'name': name + v_name,
                        'url': url
                    }
                )
                print(f"{name + v_name}'s url got")
                with open('%s_index_url.csv' % name, 'a+') as f:
                    info = '%s,%s\n' % (name + v_name, url)
                    if info in f.read():
                        continue
                    f.write(info)
            self.req_engine.set(name, '%s_index_url.csv' % name)
        print(self.result)
        return self._threading(giu, *self.result, **kwargs)

    def get_video_bytes(self, url):
        '''
        本函数根据视频流请求链接用来获得视频流数据
        :param url:
        :return:
        '''


    def download(self):
        '''
        本函数用来下载视频
        :param r_list: 包含视频链接
        :return: None
        '''
        def _download(data):
            print('%s 正在下载...' % data.get('name'))
            url = data.get('url')
            req = self.get_response()
            pattern = '"url":"(.*?)"'
            v_file_url = re.findall(pattern, le.HTML(req).xpath('//div[@class="pageMainTop20"]//script/text()')[0])[
                0].replace('\\', '')
            # print(v_file_url)
            m_url = re.findall('(https://.*?)/index.m3u8', v_file_url)[0]
            # print(m_url)
            num = 0
            while True:
                try:
                    file_c = requests.get(url=v_file_url, headers=headers, timeout=5).text.split()[-1]
                    break
                except:
                    if num < 5:
                        num += 1
                    else:
                        flag = 1
                        break
            if flag == 1:
                print('该影片来源无文件上传')
                break
            # print(file_c)
            u1 = re.findall('(.*?)/index.m3u8', file_c)[0]
            url2 = m_url + '/' + file_c
            req2 = requests.get(url2).text.split()[5::2]
            length = len(req2)
            start_time = time.perf_counter()
            for i, file in enumerate(req2):
                file_url = m_url + '/' + u1 + '/' + file
                while True:
                    try:
                        file_req = requests.get(file_url, headers=headers)
                        break
                    except:
                        time.sleep(1.3)
                        continue
                with open(os.path.join(path, r.get('name')) + '.mp4', 'ab') as f:
                    f.write(file_req.content)
                x = (i / length) * 100
                count = int(i / length * 20)
                y = '■' * count
                z = '□' * (20 - count)
                print("\r{:^3.0f}%[{}{}] {:.3f}s".format(x, y, z, time.perf_counter() - start_time), end="")
                time.sleep(1)
            f_time = time.perf_counter() - start_time
            print("\r{:^3.0f}%[{}] {:.3f}s".format(100.00, '■' * 20, f_time))
            with open('./time.log', 'a') as f:
                f.write(r.get('name') + '下载完毕，所用时间：' + '\t' + str(f_time) + 's\n')
            print('%s 已经下载完毕...\n' % r.get('name'))

        path = os.path.join(f_path, name)
        if not os.path.exists(path):
            os.mkdir(path)
        print('共有 %d 个视频需要下载' % len(r_list))

d = download_dytt_videos(kw_list=['刀剑神域', '镇魂街'])
d.search()
d.get_index_url()